/* Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.activiti.engine.impl.persistence.entity;

import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.persistence.AbstractManager;

import java.util.*;


/**
 * @author Tom Baeyens
 */
public class IdentityInfoEntityManager extends AbstractManager {

    public void deleteUserInfoByUserIdAndKey(String userId, String key) {
        IdentityInfoEntity identityInfoEntity = findUserInfoByUserIdAndKey(userId, key);
        if (identityInfoEntity != null) {
            deleteIdentityInfo(identityInfoEntity);
        }
    }

    public void deleteIdentityInfo(IdentityInfoEntity identityInfo) {
        getDbSqlSession().delete(identityInfo);
    }

    protected List<IdentityInfoEntity> findIdentityInfoDetails(String identityInfoId) {
        return Context
                .getCommandContext()
                .getDbSqlSession()
                .getSqlSession()
                .selectList("selectIdentityInfoDetails", identityInfoId);
    }

    public void setUserInfo(String userId, String userPassword, String type, String key, String value, String accountPassword, Map<String, String> accountDetails) {
        byte[] storedPassword = null;
        if (accountPassword != null) {
            storedPassword = encryptPassword(accountPassword, userPassword);
        }

        IdentityInfoEntity identityInfoEntity = findUserInfoByUserIdAndKey(userId, key);
        if (identityInfoEntity != null) {
            // update
            identityInfoEntity.setValue(value);
            identityInfoEntity.setPasswordBytes(storedPassword);

            if (accountDetails == null) {
                accountDetails = new HashMap<String, String>();
            }

            Set<String> newKeys = new HashSet<String>(accountDetails.keySet());
            List<IdentityInfoEntity> identityInfoDetails = findIdentityInfoDetails(identityInfoEntity.getId());
            for (IdentityInfoEntity identityInfoDetail : identityInfoDetails) {
                String detailKey = identityInfoDetail.getKey();
                newKeys.remove(detailKey);
                String newDetailValue = accountDetails.get(detailKey);
                if (newDetailValue == null) {
                    deleteIdentityInfo(identityInfoDetail);
                } else {
                    // update detail
                    identityInfoDetail.setValue(newDetailValue);
                }
            }
            insertAccountDetails(identityInfoEntity, accountDetails, newKeys);


        } else {
            // insert
            identityInfoEntity = new IdentityInfoEntity();
            identityInfoEntity.setUserId(userId);
            identityInfoEntity.setType(type);
            identityInfoEntity.setKey(key);
            identityInfoEntity.setValue(value);
            identityInfoEntity.setPasswordBytes(storedPassword);
            getDbSqlSession().insert(identityInfoEntity);
            if (accountDetails != null) {
                insertAccountDetails(identityInfoEntity, accountDetails, accountDetails.keySet());
            }
        }
    }

    private void insertAccountDetails(IdentityInfoEntity identityInfoEntity, Map<String, String> accountDetails, Set<String> keys) {
        for (String newKey : keys) {
            // insert detail
            IdentityInfoEntity identityInfoDetail = new IdentityInfoEntity();
            identityInfoDetail.setParentId(identityInfoEntity.getId());
            identityInfoDetail.setKey(newKey);
            identityInfoDetail.setValue(accountDetails.get(newKey));
            getDbSqlSession().insert(identityInfoDetail);
        }
    }

    public byte[] encryptPassword(String accountPassword, String userPassword) {
        // TODO
        return accountPassword.getBytes();
    }

    public String decryptPassword(byte[] storedPassword, String userPassword) {
        // TODO
        return new String(storedPassword);
    }

    public IdentityInfoEntity findUserInfoByUserIdAndKey(String userId, String key) {
        Map<String, String> parameters = new HashMap<String, String>();
        parameters.put("userId", userId);
        parameters.put("key", key);
        return (IdentityInfoEntity) getDbSqlSession().selectOne("selectIdentityInfoByUserIdAndKey", parameters);
    }

    @SuppressWarnings("unchecked")
    public List<String> findUserInfoKeysByUserIdAndType(String userId, String type) {
        Map<String, String> parameters = new HashMap<String, String>();
        parameters.put("userId", userId);
        parameters.put("type", type);
        return (List) getDbSqlSession().getSqlSession().selectList("selectIdentityInfoKeysByUserIdAndType", parameters);
    }
}
